package com.touchportfolio.loadQueue
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	
	/**
	 * The LoadQueue class is used to load object such as images,swf,xml.. One by one in a clean and proper way.
	 **/
	public class LoadQueue extends EventDispatcher
	{
		
		/* _________ PROPERTIES _______________________________ */
		
		/**
		 * custom event, that will be dispatched when there is an object loaded
		 * 
		 * @default "object loaded"
		 */
		public static const OBJECT_LOADED:String = "object loaded"
		
		/**
		 * singelton implementation
		 */
		private static var _instance:LoadQueue;
		
		/**
		 * the to be loaded objects in an array
		 */
		private static var _queue:Array = [];
		
		/**
		 * is true when the queue is bussy
		 */
		private var _loading:Boolean;
		
		/**
		 * the number of objects that has to be loaded
		 */
		private var _queueSize:uint;
		
		/**
		 * the number of object that allready loaded successfully
		 * 
		 * @default "1"
		 */
		private var _loadedObjects:uint;
		
		
		/* _________ CONSTRUCTOR ______________________________ */
		
		public function LoadQueue(e:Enforcer) { }
		
		public static function getInstance():LoadQueue
		{
			if(_instance == null) {
				_instance = new LoadQueue(new Enforcer());
			} 
			return _instance;
		}
		
		
		/* _________ GETTERS __________________________________ */
		
		/**
		 * the length of the objects in the queue
		 * 
		 * @return the length of the objects in the queue
		 */
		public function get queueSize():uint {
			return _queueSize;
		}
		
		/**
		 * the current number of loaded objects
		 * 
		 * @return the current number of loaded objects
		 */
		public function get loadedObject():uint {
			return _loadedObjects;
		}
		
		
		/* _________ PUBLIC METHODS ___________________________ */
		
		/**
		 * adds an object to the loadQueue
		 * 
		 * @param the object that you want to load
		 * 
		 * @return void
		 */
		public function addTask(loadObject:IQueueLoader):void
		{	
			// add object to queue
			_queueSize++;
			_queue.push(loadObject);
			if(_loading == false) {
				startLoading();
				_loading = true;
			}
		}
		
		
		/* _________ PRIVATE METHODS ___________________________ */
		
		/**
		 * starts to load an object in the queue, for example the first
		 * 
		 * @return void
		 */
		private function startLoading():void {
			// load the first object from the queue
			_queue[0].addEventListener(Event.COMPLETE, completeHandler);
			_queue[0].run();
		}
		
		/* _________ HANDLERS _________________________________ */
		
		/**
		 * this method will be executed when the first item from the queue is loaded. This will generate 
		 * a loop, and start immediately with loading the next object in the queue until it's completely empty
		 * 
		 * @return void
		 */
		private function completeHandler(e:Event):void {
			// update loadedObjects
			_queue[0].removeEventListener(Event.COMPLETE, completeHandler);
			_loadedObjects++;
			// dispatch custom event, when there is an object loaded
			dispatchEvent(new Event(OBJECT_LOADED));
			// remove first object from the queue
			_queue.shift();
			
			// start loading again, if the queue is not empty
			if(_queue.length != 0) {
				startLoading();
			}
			
			// queue completely loaded
			if(_queue.length == 0) {
				_loading = false;
				dispatchEvent(new Event(Event.COMPLETE));
			}

		}
		
	}
}
internal class Enforcer { }